package com.zndroid.datastore;

import android.content.Context;
import android.os.Parcelable;
import android.util.Log;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

import com.tencent.mmkv.MMKV;

import java.util.Set;

/**
 *
 * @author lzy
 * @date 2021/1/8
 *
 * 建议放弃SharedPreferences，本库借助腾讯的MMKV 底层序列化/反序列化使用 protobuf 实现，性能高，稳定性强
 *
 * 一些 Android 设备（API level 19）在安装/更新 APK 时可能出错, 导致 libmmkv.so 找不到。
 * 然后就会遇到 java.lang.UnsatisfiedLinkError 之类的 crash。有个开源库 ReLinker 专门解决这个问题，你可以用它来加载 MMKV
 * 本库不处理API=19的问题，毕竟现在手机版本很少这么低了
 */
public class Stenographer {
    private final String TAG = "DataStore";
    private MMKV KV = null;

    private Stenographer() {}
    private static class D {
        private static final Stenographer S = new Stenographer();
    }
    public static Stenographer take() {
        return D.S;
    }

    /**
     * called once at first
     * */
    public void init(@NonNull Context context) {
        String rootDir = MMKV.initialize(context);
        Log.i(TAG, rootDir);

        KV = MMKV.defaultMMKV();
    }

    public Stenographer defaults() {
        KV = MMKV.defaultMMKV();
        return this;
    }

    public Stenographer defaultsWithCrypt(String cryptKey) {
        KV = MMKV.defaultMMKV(MMKV.SINGLE_PROCESS_MODE, cryptKey);
        return this;
    }

    public Stenographer defaultsWithCrypt(String cryptKey, boolean isMulitProcess) {
        KV = MMKV.defaultMMKV(isMulitProcess ? MMKV.MULTI_PROCESS_MODE : MMKV.SINGLE_PROCESS_MODE, cryptKey);
        return this;
    }

    public Stenographer workspace(String workSpaceId) {
        KV = MMKV.mmkvWithID(workSpaceId);
        return this;
    }

    public Stenographer workspaceWithCrypt(String workSpaceId, String cryptKey) {
        KV = MMKV.mmkvWithID(workSpaceId, MMKV.SINGLE_PROCESS_MODE, cryptKey);
        return this;
    }

    /**
     * put boolean
     * */
    public void putBoolean(String key, boolean value) {
        KV.encode(key, value);
    }

    /**
     * get boolean
     * */
    public boolean getBoolean(String key, boolean defaultValue) {
        return KV.decodeBool(key, defaultValue);
    }

    /**
     * put int
     * */
    public void putInt(String key, int value) {
        KV.encode(key, value);
    }

    /**
     * get int
     * */
    public int getInt(String key, int defaultValue) {
        return KV.decodeInt(key, defaultValue);
    }

    /**
     * put float
     * */
    public void putFloat(String key, float value) {
        KV.encode(key, value);
    }

    /**
     * get float
     * */
    public float getFloat(String key, float defaultValue) {
        return KV.decodeFloat(key, defaultValue);
    }

    /**
     * put double
     * */
    public void putDouble(String key, boolean value) {
        KV.encode(key, value);
    }

    /**
     * get double
     * */
    public double getDouble(String key, double defaultValue) {
        return KV.decodeDouble(key, defaultValue);
    }

    /**
     * put long
     * */
    public void putLong(String key, long value) {
        KV.encode(key, value);
    }

    /**
     * get long
     * */
    public long getLong(String key, long defaultValue) {
        return KV.decodeLong(key, defaultValue);
    }

    /**
     * put byte[]
     * */
    public void putBytes(String key, byte[] value) {
        KV.encode(key, value);
    }

    /**
     * get byte[]
     * */
    public byte[] getBytes(String key, byte[] defaultValue) {
        return KV.decodeBytes(key, defaultValue);
    }

    /**
     * get byte[]
     * */
    public byte[] getBytes(String key) {
        return KV.decodeBytes(key);
    }

    /**
     * put String
     * */
    public void putString(String key, String value) {
        KV.encode(key, value);
    }

    /**
     * get String
     * */
    public String getString(String key, String defaultValue) {
        return KV.decodeString(key, defaultValue);
    }

    /**
     * put String Set
     * */
    public void putStringSet(String key, Set<String> value) {
        KV.encode(key, value);
    }

    /**
     * get String Set
     * */
    public Set<String> getStringSet(String key, Set<String> defaultValue) {
        return KV.decodeStringSet(key, defaultValue);
    }

    /**
     * get String Set
     * */
    public Set<String> getStringSet(String key) {
        return KV.decodeStringSet(key);
    }

    /**
     * put Parcelable
     * */
    public void putParcelable(String key, Parcelable value) {
        KV.encode(key, value);KV.async();
    }

    /**
     * get Parcelable
     * */
    public <T extends Parcelable> T getParcelable(String key, Class<T> tClass) {
        return KV.decodeParcelable(key, tClass);
    }

    /**
     * get Parcelable
     * */
    public <T extends Parcelable> T getParcelable(String key, Class<T> tClass, @Nullable T defaultValue) {
        return KV.decodeParcelable(key, tClass, defaultValue);
    }

    /**
     * clear all of current MMKV
     * */
    public void clearAll() {
        KV.clearAll();
    }

    /**
     * remove by key
     * */
    public void removeByKey(String key) {
        KV.removeValueForKey(key);
    }

    /**
     * remove by keys
     * */
    public void removeByKeys(String[] keys) {
        KV.removeValuesForKeys(keys);
    }

}